#include <cv.h>
#include <highgui.h>

#include "HandInterface.hpp"

#include <iostream>

using namespace cv;

class TrackerRunner {
public:
	
	AbstractHandTracker *ht;
	cv::Ptr< cv::VideoCapture > capPtr;
	cv::Mat frame;
	HandLocaliser* hl;
	cv::Rect trackingRect;
	
	int run();
	
protected:
	void clean();
	int localise();
	void setNextFrame();
};



void TrackerRunner::clean() {
	delete hl;
	delete ht;
}

void TrackerRunner::setNextFrame() {
	(*capPtr) >> frame;
	flip(frame, frame, 1);
}

int TrackerRunner::localise() {
	
	hl = new HandLocaliser();
	
	
	try {
		setNextFrame();
		trackingRect = hl->localiseFace( frame );
		//trackingRect = hl->localiseHand( frame );
		cout << "Face found" << endl;
	}
	catch (cv::Exception e) {
		if ( e.code == HI_ERR_NOFACEFOUND ) {
			delete hl;
			return -1;
		} else {
			throw;
		}
	}
	
	//forcing rectangle to stay inside frame
	if ( trackingRect.x < 0 ) trackingRect.x = 0;
	if ( frame.cols < trackingRect.x + trackingRect.width ) trackingRect.x = frame.cols - trackingRect.width;
	if ( trackingRect.y < 0 ) trackingRect.y = 0;
	if ( frame.rows < trackingRect.y + trackingRect.height ) trackingRect.y = frame.rows - trackingRect.height;
	
	return 1;
}

int TrackerRunner::run() {
	
	HiVisualiser::addWindow("handtracker");
	HiVisualiser::moveWindow("handtracker",500,200);
	
	capPtr = Ptr< VideoCapture >(new VideoCapture(0)); // open the default camera
	
	bool captureSizeSet = capPtr->set( CV_CAP_PROP_FRAME_WIDTH , 640 );
	captureSizeSet &= capPtr->set( CV_CAP_PROP_FRAME_HEIGHT , 480 );
	
    if(!capPtr->isOpened() || !captureSizeSet)  // check if we succeeded
        return -1;
	
	char c = waitKey(1);
	
	while (c != 27) {
		
		while (c != 27 && localise() == -1 ) {}
		
		
		Ptr< GeometricGestureClassifier > internalClassifier = Ptr< GeometricGestureClassifier >( new BoostGestureClassifier( "short", "short", hl->getProbabilityTransformer() ) );
		
//		//paramset2
//		ht = HandTracker::init( false, 10.0, 0.1, 10.0, 10.0,
//							   trackingRect, frame, Ptr< GeometricGestureClassifier >( new HysteresisGestureClassifier( internalClassifier, 10, 10 ) ) );
		
		//paramset2
		ht = HandTracker::init( false, 10.0, 0.1, 10.0, 10.0,
							   trackingRect, frame, internalClassifier );
		
//		//paramset2
//		ht = HandTracker::init( false, 1.0, 0.1, 10.0, 10.0,
//									  trackingRect, frame, Ptr< GeometricGestureClassifier >( new GeometricGestureClassifier( hl->getProbabilityTransformer() ) ) );
		
		
		//paramset1
//		ht = HandTrackerLKHSVCD::init( false, 5.0, 0.5, 20.0, 10.0,
//									  trackingRect, frame, Ptr< GeometricGestureClassifier >( new GeometricGestureClassifier( hl->getProbabilityTransformer() ) ) );
		
//		ht = HandTrackerLKHSVCD::init( false, 5.0, 0.5, 20.0, 50.0,
//									  trackingRect, frame, Ptr< GeometricGestureClassifier >( new GeometricGestureClassifier( hl->getProbabilityTransformer() ) ) );
		
		while (c != 27) {
			// -- tracking frame -- //
			trackingRect = ht->track( frame );
			
			if ( ht->isHandActive() ) {
				circle(HiVisualiser::windowMatrixMap["handtracker"], Point(5, 5), 4, Scalar( 0, 0, 255 ), 2);
			} else {
				circle(HiVisualiser::windowMatrixMap["handtracker"], Point(5, 5), 1, Scalar( 255, 0, 0 ), 2);
			}
			HiVisualiser::refreshWindow( "handtracker" );
			setNextFrame();
			c = waitKey(1);
		}
		
		clean();
	}
	
	return 1;
}

int main() {
	
	TrackerRunner* runner = new TrackerRunner();
	
	int status = runner->run();
	
	delete runner;
	
	return status;
}


